package com.zhuchang.self_rpc.test.democoding;

import io.netty.buffer.ByteBuf;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

/**
 * @Author RenPu
 * @Date 2022/2/7 18:26
 * @Version 1.0
 * @Description: NIO模拟实现聊天IM-群聊客户端1
 **/
public class GroupChatClient {

  //1：服务端ip+port
    private static final String HOST="127.0.0.1";
    private static final int PORT=6667;
  //2：定义socketChannel对象
    private SocketChannel socketChannel;
  //3：定义客户端名称
    private String userName;
  //4：定义选择器对象监听channel可获取的事件
    private Selector selector;

  //初始化成员变量参数
  public GroupChatClient() {

    try {
      this.selector=Selector.open();  //与选择器创建连接
      this.socketChannel=SocketChannel.open(new InetSocketAddress(HOST,PORT)); //与服务端创建连接
      socketChannel.configureBlocking(false); //设置为非阻塞
      SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);//将socketChannel注册到Selector上
      this.userName=socketChannel.getLocalAddress().toString().substring(1); //设定Username
      System.out.println(userName+"is ok......请开始对话......");

    } catch (IOException ioException) {
      ioException.printStackTrace();
    }
  }

  //5：客户端通过socketChannel+byteBuffer发送数据
  public void sendRomateMessage(String content){

       content=userName+"说："+content;
    try {
//      Socket socket = socketChannel.socket();

//设置setTcpNoDelay为false时, 就会开启Nagle算法：将通信中小数据包收集起来，组成一个大数据包一次发送出去，
// 优点避免大量的小包,频繁传递引起网络拥塞，缺点就是数据会影响数据的时效性
//设置setTcpNoDelay为true时,就会关闭Nagle算法 ，将数据包立马通过网络传输发送出去
//      socket.setTcpNoDelay(false);

//设置setKeepAlive为true，可以避免客户端，服务端有一方断开连接，导致另一端无感知
//导致被断开端一直保存着网络连接资源，当设置为true时，周期为2小时内如果双方没有任何的通信
//此时会发送一个探测包，根据探测包的结果进行决定是保持连接，断开连接，重新连接
//     socket.setKeepAlive(true);

      socketChannel.write(ByteBuffer.wrap(content.getBytes()));
    } catch (IOException ioException) {
      ioException.printStackTrace();
    }
  }


  //6：客户端读取服务端发来的数据
  public void readRomateMessage(){


    int count = 0;
    try {
      count = selector.select();  //获取选择器可以获取事件内容的个数
      if(count>0) {
        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
        while (iterator.hasNext()){
          SelectionKey next = iterator.next();
          SocketChannel channel =(SocketChannel) next.channel();
          ByteBuffer  byteBuffer = ByteBuffer.allocate(1024);
          channel.read(byteBuffer);

          System.out.println(new String(byteBuffer.array()).trim());
        }
        iterator.remove(); //删除当前的 selectionKey,防止重复操作
      }else {
        System.out.println("没有可用的通道.........");
      }
    } catch (IOException ioException) {
      ioException.printStackTrace();
    }
    }



  public static void main(String[] args) {

    //定义一个线程每隔3秒，从服务器端获取一次数据
    GroupChatClient groupChatClient = new GroupChatClient();


    //客户端读取服务端发来的数据
    new Thread(()->{
      try {
        groupChatClient.readRomateMessage();
        Thread.sleep(3000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }).start();



    //客户端通过socketChannel+byteBuffer发送数据
    Scanner scanner = new Scanner(System.in);
    while (scanner.hasNextLine()){
      String content = scanner.nextLine();
      groupChatClient.sendRomateMessage(content);
    }


  }


}



